package com.kehutong.auth.controller;

import com.kehutong.auth.dao.UserDao;
import com.kehutong.auth.enums.AccountStatus;
import com.kehutong.auth.service.SmsCodeService;
import com.kehutong.common.DoveClient;
import com.kehutong.common.ExcelUtil;
import com.kehutong.common.PageUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.coraframework.authz.HasPermission;
import org.coraframework.authz.Subject;
import org.coraframework.authz.exception.AuthenticationException;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.mvc.MvcAction;
import org.coraframework.mvc.http.Bean;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.execute.Condition;
import org.coraframework.orm.jdbc.execute.QueryCondition;
import org.coraframework.orm.jdbc.execute.entity.FindArray;
import org.coraframework.orm.jdbc.execute.entity.FindPage;
import org.coraframework.util.EnumUtil;
import org.coraframework.util.Objects;

import com.kehutong.auth.entity.User;
import com.kehutong.common.util.Token;
import org.coraframework.util.time.TimeUtil;

import java.io.File;
import java.sql.Timestamp;

import java.util.*;
import java.util.stream.Collectors;

@MvcAction
@ReqMapping("/admin/auth_user")
public class UserController {

	@Inject
    private JdbcSession jdbcSession;
	@Inject
	private DoveClient doveClient;
	@Inject
	private UserDao userDao;
	@Inject
	private SmsCodeService smsCodeService;

	public final static String[] EXCEL_IMPORT_HEADER = {"姓名","手机号","成员账号","企业微信","性别","生日","邮箱","城市","签名","微信","添加时间","状态"};

	@ReqMapping("/getToken")
	public Object getToken(Token token) {
		if(Objects.isNull(token)){
			return null;
		}

	    User user = Pool.get(User.class, token.getUuid());
        token.setHeadUrl(user.getAvatar());

		token.setMobile(user.getMobile());
		return token;
	}

	@ReqMapping("/listByRole")
    public Object listByRole(Token token, JSONObject params, String roleNo) {
		params.put("corpNo", token.getCompanyNo());
    	return jdbcSession.findArray(User.class)
    			.eq(params, "corpNo")
    			.eq("deleted", false)
    			.like("roles", roleNo)
    			.exe();
    }

	@ReqMapping("/getAdmin")
	public Object getAmind(Token token) throws Exception {

		QueryCondition query = Condition.createQuery(false);
		query.eq("corpNo", token.getCompanyNo());

		List<Map<String, Object>> users = userDao.getAdmin(query);

        Map<String, Map<String, Object>> userMap = new HashMap<>();
		users.forEach(item -> {
			userMap.put(item.get("id").toString(), item);
		});

		List<String> ids = users.stream().map(item ->{
			return (String) item.get("id");
		}).collect(Collectors.toList());

		if(Objects.nonEmpty(ids)){
			List<JSONObject> list = getEmployee(ids);
			list.forEach(item -> {
				Map<String, Object> map = userMap.get(item.getString("id"));
				if(Objects.nonEmpty(map)){
					item.put("mobile", map.get("mobile"));
				}
			});
			return list;
		}

		return Result.success();
	}

	@ReqMapping("/getChildAmind")
	public Object getChildAmind(Token token, JSONObject jsonObject) throws Exception {
		List<User> users = jdbcSession.findArray(User.class)
				.isNotNull("roles")
				.eq("corpNo", token.getCompanyNo())
				.eq("deleted", false)
				.exe();

		List<String> ids = users.stream().map(User::getId).collect(Collectors.toList());

		if(Objects.nonEmpty(ids)){
			List<JSONObject> list = getEmployee(ids);
			return Result.success(PageUtils.buildPage(jsonObject,list));
		}
		return Result.success();
	}

	@ReqMapping("/transfer")
	public Object transfer(Token token, JSONObject jsonObject){
		// 修改新管理员的角色
		User newAdmin = Pool.get(User.class, jsonObject.getString("newUserId"));
		Set<String> roles = new HashSet<>();
		roles.add("5");
		newAdmin.setRoles(roles);
		jdbcSession.updateById(newAdmin);

		// 修改旧管理员的角色
		User oldAdmin = Pool.get(User.class, jsonObject.getString("oldUserId"));
		if(Objects.isNull(oldAdmin)){
			return Result.error(0, "未获取到转让人信息");
		}

		oldAdmin.setRoles(new HashSet<>());
		jdbcSession.updateById(oldAdmin);

		return Result.success();
	}

	public List<JSONObject> getEmployee(List<String> ids) throws Exception {
		JSONObject result = doveClient.post("/basic/employee/service/list", http->{
			JSONObject body = new JSONObject();
			body.put("id", ids);

			body.put("pageNo", 1);
			body.put("pageSize", 1000000);

			http.setBody(body.toString());
		});

		JSONArray data = result.getJSONObject("data").getJSONArray("list");
		if (Objects.isNull(data)) {
			return null;
		}

		return JSONObject.parseArray(data.toJSONString(), JSONObject.class);
	}

    @HasPermission("auth:user:view")
    @ReqMapping("/list")
    public Object list(Token token, JSONObject jsonObject) {
    	FindPage<User> find = jdbcSession.findPage(User.class)
				.eq(jsonObject, "id",  "email", "phone", "corpNo")
				.like(jsonObject, "name", "login_name", "mobile")
				.eq("deleted", false)
				.order("createTime", "DESC")
				.page(jsonObject);

		if (Objects.nonEmpty(token.getCompanyNo())) {
			find.eq("corpNo", token.getCompanyNo());
		}
		
    	return find.exe();
    }
    
    @HasPermission("auth:user:view")
    @ReqMapping("/get")
    public Object getById(User user) {
    	if (user == null || user.isDeleted()) {
    		return Result.error(0, "对象不存在");
    	}

    	return user;
    }

	@ReqMapping("/export")
	public Object export(Token token, JSONObject jsonObject) throws Exception {
		FindArray<User> find = jdbcSession.findArray(User.class)
				.in(jsonObject, "id")
				.eq(jsonObject,  "email", "phone", "corpNo")
				.like(jsonObject, "name", "login_name", "mobile")
				.eq("deleted", false)
				.order("createTime", "DESC");

		if (Objects.nonEmpty(token.getCompanyNo())) {
			find.eq("corpNo", token.getCompanyNo());
		}

		List<User> list = find.exe();

		Workbook wb = generateWorkBook(list);

		File tmpFile = ExcelUtil.writeXlsFile(wb, "用户信息", ".xlsx");

		return Result.download(tmpFile);
	}

    @Bean(newInstance=true, copy=true)
    @HasPermission("auth:user:edit")
    @ReqMapping("/save")
    public Object save(Token token, User user, String password) {
    	User other = jdbcSession.findOne(User.class)
    			.eq("login_name", user.getLogin_name())
    			.exe();
    	if (Objects.nonNull(other)) {
    		return Result.error(10301, "会员已存在");
    	} 
    	
    	setPassword(user, password);
    	setCorp(user, token);
		jdbcSession.insert(user);
    	
    	return Result.success();
    }

	/**
	 * 提醒用户设置资料
	 * @param user
	 * @return
	 */
	@ReqMapping("/remind")
	public Object remind(User user, Token token) throws Exception {
		user.setRemindTime(new Timestamp(TimeUtil.timeMillis()));
		jdbcSession.updateById(user);

		token.setRemindTime(user.getRemindTime().getTime());

		JSONObject rs = doveClient.post("/kht-bin/session/service/login", http -> {
			http.setBody(token.toJSON().toJSONString());
		});

		if (rs.getInteger("code") != 200) {
			throw new AuthenticationException("login fail: " + rs.getString("message"));
		}

		return Result.success();
	}
    
    @Bean(copy=true)
    @HasPermission("auth:user:edit")
    @ReqMapping("/update")
    public Object update(Token token, User user, String password) {
    	setPassword(user, password);
    	setCorp(user, token);
		jdbcSession.updateById(user);
    	
        return Result.success();
    }

    @HasPermission("auth:user:edit")
    @ReqMapping("/changePasswd")
    public Object validatePwd(User user, String oldPassword, String newPassword) {
		if (Objects.isNull(user)) {
			return Result.error(2001, "用户不存在");
		}
		
		if (!user.getPassword().equals(Subject.encrypt(oldPassword))) {
			return Result.error(2001, "修改密码失败，旧密码错误");
		}

		setPassword(user, newPassword);
		jdbcSession.updateById(user);
    			
		return Result.success();
    }
    
    @HasPermission("auth:user:edit")
    @ReqMapping("/delete")
    public Object deleteById(User user) {
    	if (user != null) {
    		user.setDeleted(Boolean.TRUE);
    		jdbcSession.updateById(user);
    	}
    	
        return Result.success();
    }

	@HasPermission("auth:user:edit")
	@ReqMapping("/updateStautus")
	public Object updateStautus(User user, JSONObject jsonObject) {
		if (user != null) {
			AccountStatus status = EnumUtil.getEnum(AccountStatus.class, jsonObject.getString("status"));
			user.setStatus(status);
			jdbcSession.updateById(user);
		}

		return Result.success();
	}

	public XSSFWorkbook generateWorkBook(List<User> users) throws Exception {
		// 生成模板文件
		XSSFWorkbook wb = new XSSFWorkbook();
		// 设置头信息
		Sheet sheet = wb.createSheet();

		Row headerRow = sheet.createRow(0);
		for (int i = 0; i < EXCEL_IMPORT_HEADER.length; i++) {
			Cell cell = headerRow.createCell(i);
			cell.setCellValue(EXCEL_IMPORT_HEADER[i]);
		}

		int cellNum = 0;
		for (int i = 0; i < users.size(); i++) {
			cellNum = 0;
			User item = users.get(i);
			Row row = sheet.createRow(i + 1);
			row.createCell(cellNum++).setCellValue(item.getName());
			row.createCell(cellNum++).setCellValue(item.getMobile());
			row.createCell(cellNum++).setCellValue(item.getLogin_name());
			row.createCell(cellNum++).setCellValue(item.getUserId());
			row.createCell(cellNum++).setCellValue(Objects.nonNull(item.getGender()) ? item.getGender().getDesc() : "");
			row.createCell(cellNum++).setCellValue(item.getBirthday());
			row.createCell(cellNum++).setCellValue(item.getEmail());
			row.createCell(cellNum++).setCellValue(Objects.nonEmpty(item.getAreaNames()) ? String.join("-", item.getAreaNames()) : "");
			row.createCell(cellNum++).setCellValue(item.getSign());
			row.createCell(cellNum++).setCellValue(item.getWeChat());
			row.createCell(cellNum++).setCellValue(item.getCreateTime().toString());
			row.createCell(cellNum++).setCellValue(item.getStatus().getDesc());
		}

		// 自动列宽
		for (int i = 0; i < cellNum; i++) {
			ExcelUtil.autoSizeColumn(sheet, i);
		}
		return wb;

	}
    
//    private JSONResult setProperty(User item, JSONObject jsonObject) {
//    	Set<String> roles = getRoles(jsonObject);
//    	item.setRoles(roles);
//    	if (item.isAdmin() || (item.isAdminRole() && Objects.nonEmpty(item.getCompanyNo()))) {
//    		item.setCompanyNo(null);
//    		item.setCompanyName(null);
//    	} else {
//    		item.setCompanyNo(jsonObject.getString("companyNo"));
//    		item.setCompanyName(jsonObject.getString("companyName"));
//    	}
//    	
//		String passwd = jsonObject.getString("password");
//		if (Objects.isTrimNotEmpty(passwd)) {
//			item.setPassword(Subject.encrypt(passwd));
//		}
//		
//		item.setNo(jsonObject.getString("no"));
//		item.setName(jsonObject.getString("name"));
//		item.setLogin_name(jsonObject.getString("login_name"));
//		item.setEmail(jsonObject.getString("email"));
//		item.setMobile(jsonObject.getString("mobile"));
//		item.setPhone(jsonObject.getString("phone"));
//		item.setRemark(jsonObject.getString("remark"));
//
//		return Result.success();
//	}
    
//	private Set<String> getRoles(JSONObject jsonObject) {
//		JSONArray jsonArray = jsonObject.getJSONArray("roles");
//		if (Objects.isEmpty(jsonArray)) {
//			return new HashSet<>();
//		}
//		
//		Set<String> roleList = new LinkedHashSet<>();
//		for (int i = 0; i < jsonArray.size(); i ++) {
//			String roleNo = jsonArray.getString(i);
//			if (Root.isRoot(roleNo)) {
//				roleList.clear();
//				roleList.add(roleNo);
//				return roleList;
//			}
//			
//			final Role role = Pool.get(Role.class, jsonArray.getString(i));
//			if (role != null && !role.isDeleted()) {
//				roleList.add(role.getId());
//			}
//		}
//		return roleList;
//	}
    
    private void setPassword(User user, String password) {
    	if (Objects.nonEmpty(password)) {
    		user.setPassword(Subject.encrypt(password));
    	}
    }
    
    private void setCorp(User user, Token token) {
    	if (Objects.isEmpty(user.getCorpNo())) {
    		user.setCorpNo(token.getCompanyNo());
    		user.setCorpName(token.getCompanyName());
    	}
    }
	
}
